package models;

import siena.Filter;
import siena.Id;
import siena.Model;
import siena.Query;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.jar.Attributes;
import java.util.logging.Logger;


public class Game extends Model {

    private static Logger logger = Logger.getLogger(Game.class.getName());

    public Long currentEvaluationId = null;

    public boolean completed = false;

    public String name = "";

    @Id
    public Long id;

    @Filter("game")
    public Query<Evaluation> evaluations;

    public static Game createGame(List<Deck> decks) {

        Game game = new Game();
        game.insert();
        logger.info("Created game: " + game);
        game.name = "";
        for (Deck deck : decks) {
            if( deck.equals(decks.get(0))) {
                game.name = deck.name;
            } else {
                game.name = game.name + " + " + deck.name;
            }

            for (Card card : deck.getCards()) {
                Evaluation evaluation = new Evaluation(game, card);
                evaluation.insert();
            }
        }
        game.completed = false;
        return game;
    }

    public static Game findById(Long id) {
        return all().filter("id", id).get();
    }

    public static List<Game> findAllUncompleted() {
        return all().filter("completed", false).fetch();
    }

    @Override
    public void delete() {
        for (Evaluation evaluation : Evaluation.findByGame(this)) {
            evaluation.delete();
        }
        super.delete();
    }

    static Query<Game> all() {
        return Model.all(Game.class);
    }

    public static List<Game> findAll() {
        return all().fetch();
    }

    public Evaluation getCurrentEvaluation() {
        if (currentEvaluationId == null) {
            setRandomEvaluation();
        }
        return Evaluation.findById(currentEvaluationId);
    }

    public void setRandomEvaluation() {
        ArrayList<Evaluation> unCorrect = findAllUncompletedEvaluations();
        if (unCorrect.size() > 1 && currentEvaluationId != null) {
            unCorrect.remove(getCurrentEvaluation());
        }
        Collections.shuffle(unCorrect);
        currentEvaluationId = unCorrect.get(0).id;
        this.update();
    }

    public void updateUserEvaluation(Evaluation.UserEvaluation userEvaluation) {
        Evaluation currentEvaluation = getCurrentEvaluation();
        currentEvaluation.userEvaluation = userEvaluation;
        currentEvaluation.update();
        completed = calcCompleted();
        update();
    }

    private boolean calcCompleted() {
        ArrayList<Evaluation> unCompleted = findAllUncompletedEvaluations();
        return unCompleted.size() == 0;
    }

    private ArrayList<Evaluation> findAllUncompletedEvaluations() {
        ArrayList<Evaluation> unCompleted = new ArrayList<Evaluation>();
        unCompleted.addAll(Model.all(Evaluation.class).filter("game", this).filter("userEvaluation", Evaluation.UserEvaluation.INVALID).fetch());
        unCompleted.addAll(Model.all(Evaluation.class).filter("game", this).filter("userEvaluation", Evaluation.UserEvaluation.NONE).fetch());
        return unCompleted;
    }

    public GameStatistics calcGameStatistics() {
        List<Evaluation> evals = Evaluation.findByGame(this);
        int incorrect = 0;
        int correct = 0;
        int total = 0;
        int unanswered = 0;

        for (Evaluation eval : evals) {
            total++;
            if (eval.userEvaluation == Evaluation.UserEvaluation.NONE) {
                unanswered++;
            } else if (eval.userEvaluation == Evaluation.UserEvaluation.CORRECT) {
                correct++;
            } else if (eval.userEvaluation == Evaluation.UserEvaluation.INVALID) {
                incorrect++;
            } else {
                throw new IllegalArgumentException("Unexpected user evaluation type:" + eval.userEvaluation);
            }
        }
        return new GameStatistics(incorrect, correct, unanswered, total);
    }

    public Collection<Card> cards() {
        return Evaluation.findCardsByGame(this);
    }

    @Override
    public String toString() {
        return "Game{" +
                "id=" + id +
                '}';
    }
}
